#include "stdafx.h"
#include "Operator.h"
#include "InstanceTouch.h"
#include <math.h>
DECL_INSTANCE_TOUCH(ETouch_Operator);

struct  OperatorDefReflectionRegister
{
	OperatorDefReflectionRegister()
	{
		REGISTER_REFLECTION_MEMBER(Operator,m_iID,INVALID_ID).Editor_SetAsPrimaryKey();
		REGISTER_REFLECTION_MEMBER(Operator,m_sDisplayName,std::string("DefaultName")).Editor_SetAsDisplayName();
		REGISTER_REFLECTION_MEMBER(Operator,m_eParam0,eEvaluation_P0).Editor_SetAsEnumation<EEvaluationType>("Param0");
		REGISTER_REFLECTION_MEMBER(Operator,m_iOperation0,INVALID_ID).Editor_SetAsForeignKey(eDefGroup_Default,eDefaultDef_Operator,"Param0");

		REGISTER_REFLECTION_MEMBER(Operator,m_eOperator,eOperator_First).Editor_SetAsEnumation<EOperator>("Operator");

		REGISTER_REFLECTION_MEMBER(Operator,m_eParam1,eEvaluation_P0).Editor_SetAsEnumation<EEvaluationType>("Param1");
		REGISTER_REFLECTION_MEMBER(Operator,m_iOperation1,INVALID_ID).Editor_SetAsForeignKey(eDefGroup_Default,eDefaultDef_Operator,"Param1");

		

		GlobalClassManager::Instance().RegisterClass(Operator::s_GetReflection(),eDefaultDef_Operator);
		GlobalDefManager::Instance().RegisterDefManger(&OperatorManager::Instance());

	}
}___OperatorDefReflectionRegister;

rewrite  void Operator::OnArchieveReaded()
{
	m_pOperator0=OperatorManager::Instance().LookupItem(m_iOperation0);
	m_pOperator1=OperatorManager::Instance().LookupItem(m_iOperation1);
}

double Operator::Evaluate( const FormulaEnv& rEnv ) const
{
	double fParam0=CalParam(rEnv,m_eParam0,m_pOperator0);
	double fParam1=CalParam(rEnv,m_eParam1,m_pOperator1);
	switch(m_eOperator)
	{
	case eOperator_Plus:
		{
			return fParam0+fParam1;
		}
	case eOperator_Sub:
		{
			return fParam0-fParam1;
		}
	case eOperator_Multiply:
		{
			return fParam0*fParam1;
		}
	case eOperator_Division:
		{
			if( fabs( fParam1) > 1e-6 )
				return fParam0/fParam1;
			else
				return fParam0;
		}
	case eOperator_Random:
		{
			double fRange=fParam1-fParam0;
			double fAdd=fRange*(rand()%1000)/1000.f;
			return fParam0+fAdd;
		}
	case eOperator_First:
		{
			return fParam0;
		}
	case eOperator_Second:
		{
			return fParam1;
		}
	case eOperator_AbsFirst:
		{
			return ::fabs(fParam0);
		}
	case eOperator_Min:
		{
			return fParam0<fParam1?fParam0:fParam1;
		}
	case eOperator_Max:
		{
			return fParam0>fParam1?fParam0:fParam1;
		}
	case eOperator_Pow:
		{
			return pow(fParam0,fParam1);
		}
	default:
		{
			return fParam0;
		}
	}

}

double Operator::CalParam( const FormulaEnv& rEnv,EEvaluationType eType,Operator * pOperator ) const
{
	switch(eType)
	{
	case eEvaluation_P0:
	case eEvaluation_P1:
	case eEvaluation_P2:
	case eEvaluation_P3:
		{
			return rEnv.m_vParams[eType];
		}
	case eEvaluation_V0:
	case eEvaluation_V1:
	case eEvaluation_V2:
	case eEvaluation_V3:
		{
			return rEnv.m_vValues[eType-4];
		}
	case eEvaluation_Operation:
		{
			if(pOperator) 
			{
				return pOperator->Evaluate(rEnv);
			}
			else
			{
				return 0.f;
			}
		}
	default: 
		return 0.f;
	};
}